/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package com.inspur.edp.metadata.service.dev.core.entity.validate;

import com.inspur.edp.lcm.metadata.spi.entity.MetadataDependencyDetail;
import com.inspur.edp.metadata.service.dev.core.entity.GspMetadataCache;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 元数据关系有向图
 *
 * @author sunhongfei
 */
public class MetadataDirectGraph {

    /**
     * 用来存储顶点
     * T做为标识，vertext作为实际的顶点
     */
    private final Map<String, MetadataVertex> vertexMap = new ConcurrentHashMap<>();

    //下面与图的顶点相关
    /**
     * 返回图的顶点的迭代器
     *
     * @return 顶点的迭代器
     */
    public Iterator<MetadataVertex> getVertexIterator() {
        return vertexMap.values().iterator();
    }

    /**
     * 获取图顶点的 metadataId集合, 为防止外部修改,将其处理到新Set中
     *
     * @return 图顶点的metadataId集合
     */
    public Set<String> getVertexMetadataIds() {
        return new HashSet<>(vertexMap.keySet());
    }

    /**
     * 在图中插入节点，节点的标识为metadataId
     *
     * @param metadataId 插入节点标识
     * @return 如果图中不存在该节点，则插入，返回true<br>
     * 如果图中已经存在该节点，则更新权值，返回false
     */
    public MetadataVertex addVertex(String metadataId, GspMetadataCache content) {
        return vertexMap.put(metadataId, new MetadataVertex(metadataId, content));
    }

    public MetadataVertex removeVertex(String metadataId) {
        return vertexMap.remove(metadataId);
    }

    /**
     * 根据标识metadataId获取对应的节点
     *
     * @param metadataId 节点标识
     * @return 图中已存在的节点
     */
    public MetadataVertex getVertex(String metadataId) {
        return vertexMap.get(metadataId);
    }


    //下面与图的边相关

    /**
     * 在图中加入一条边，如果isDirect为true，则为有向图，则<br>
     * 建立一条以begin作为标识的节点开始的边，以end作为标识的节点结束<br>
     * 如果isDirect为false，则为无向图，则<br>
     * 建立两条边，一条以begin开始，到end ，一条以end开始，到begin
     *
     * @param begin 开始节点的标识
     * @param end   结束节点的标识
     * @return 如果没有对应的边，则加入对应的边，返回true<br>
     * 如果有对应的边，则返回false
     * 如果没有以begin或者end标识的顶点，则直接返回false
     */
    public boolean addEdge(String begin, String end, MetadataDependencyDetail content) {
        MetadataVertex beginMetadataVertex = vertexMap.get(begin);
        if (beginMetadataVertex == null) {
            //如果没有以begin或者end标识的顶点，则直接返回false
            return false;
        }
        //有向图和无向图都要建立begin到end的边
        //如果顶点已经与endVertex连接，那么将会更新权值，result=false
        //如果顶点没有与endVertex相连，则互相连接，result=true

        return beginMetadataVertex.connect(end, content);
    }
}